package com.ywk.rabbitmqProd.base.config;


import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * 参考连接：https://www.jianshu.com/p/3346ce00828d
 *
 * rabbitmq使用方法：先声明队列和交换机，通过相应的方法进行两者绑定，MQSender发送消息时通过交换机发送给对应的队列，
 * MQReceiver通过注解 @RabbitListener去监听对应的队列是否有消息，有则执行相应方法处理消息
 *
 * Exchange 有4个类型：Direct，Topic，Fanout，Headers
 *
 */
@Configuration
@Slf4j
public class MQConfig {


    public static final String QUEUE = "queue";

    public static final String DIRECT_QUEUE1 = "direct.queue1";
    public static final String DIRECT_QUEUE2 = "direct.queue2";
    public static final String DIRECT_EXCHANGE = "direct.Exchange";
    public static final String DIRECT_ROUTING_KEY1 = "direct.routingKey1";
    public static final String DIRECT_ROUTING_KEY2 = "direct.routingKey2";


    public static final String FANOUT_QUEUE1 = "fanout.queue1";
    public static final String FANOUT_QUEUE2 = "fanout.queue2";
    public static final String FANOUT_EXCHANGE = "fanoutExchange";

    public static final String TOPIC_QUEUE1 = "topic.queue1";
    public static final String TOPIC_QUEUE2 = "topic.queue2";
    public static final String TOPIC_EXCHANGE = "topicExchange";

    public static final String HEADER_QUEUE = "header.queue";
    public static final String HEADERS_EXCHANGE = "headersExchange";

    public static final String BUSINESS_QUEUE = "business_queue";

    /**
     * 发送者直接将信息发送给接收者队列
     * */
    @Bean
    public Queue queue() {

        log.info("执行方法MQConfig.queue(),初始化RabbitMQ队列：queue");
        return new Queue(QUEUE, true);
    }


    /**
     * Direct：（广播模式<精确匹配>:一对多[一个生产者多个队列]）
     * 将消息中的 Routing key与该 Exchange 关联的所有 Binding 中的 Routing key 进行比较，如果相等，
     * 则发送到该 Binding 对应的 Queue 中
     * @return
     */
    @Bean
    public Queue directQueue1(){
        // durable:是否持久化,默认是false,持久化队列：会被存储在磁盘上，当消息代理重启时仍然存在，暂存队列：当前连接有效
        // exclusive:默认也是false，只能被当前创建的连接使用，而且当连接关闭后队列即被删除。此参考优先级高于durable
        // autoDelete:是否自动删除，当没有生产者或者消费者使用此队列，该队列会自动删除。
        //   return new Queue("TestDirectQueue",true,true,false);

        //一般设置一下队列的持久化就好,其余两个就是默认false
        return new Queue(DIRECT_QUEUE1,true);
    }
    @Bean
    public Queue directQueue2(){
        return new Queue(DIRECT_QUEUE2,true);
    }
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange(DIRECT_EXCHANGE,true,false);
    }
    @Bean
    public Binding directBinding1(){
        return BindingBuilder.bind(directQueue1()).to(directExchange()).with(DIRECT_ROUTING_KEY1);
    }
    @Bean
    public Binding directBinding2(){
        return BindingBuilder.bind(directQueue2()).to(directExchange()).with(DIRECT_ROUTING_KEY2);
    }

    /**
     * Fanout 模式 交换机 Exchange（广播模式:一对多[一个生产者多个队列]）
     * 队列通过绑定 FanoutExchange（FanoutBinding1()做绑定的）就能接受到发送者发送的消息
     * */
    @Bean
    public Queue fanoutQueue1(){
        return new Queue(FANOUT_QUEUE1,true);
    }
    @Bean
    public Queue fanoutQueue2(){
        return new Queue(FANOUT_QUEUE2,true);
    }
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange(FANOUT_EXCHANGE);
    }
    @Bean
    public Binding FanoutBinding1() {
        return BindingBuilder.bind(fanoutQueue1()).to(fanoutExchange());
    }
    @Bean
    public Binding FanoutBinding2() {
        return BindingBuilder.bind(fanoutQueue2()).to(fanoutExchange());
    }



    /**
     * Topic 模式 交换机 Exchange（匹配模式：一对多）
     * 发送者将信息交由方法 TopicExchange 对象，队列通过 RoutingKey 绑定交换机 TopicExchange 对象，
     * 该对象按 RoutingKey 分发给两个接收者队列 TOPIC_QUEUE1 和 TOPIC_QUEUE2 (能发送一条消息给多个队列)
     *
     * 通配符的匹配规则如下：
     *  Routing key必须是一串字符串，每个单词用“.”分隔；
     *  符号“#”表示匹配一个或多个单词；
     *  符号“*”表示匹配一个单词。
     * */
    @Bean
    public Queue topicQueue1(){
        return new Queue(TOPIC_QUEUE1,true);
    }
    @Bean
    public Queue topicQueue2(){
        return new Queue(TOPIC_QUEUE2,true);
    }
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange(TOPIC_EXCHANGE);
    }
    @Bean
    public Binding topicBinding1(){
        return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with("topic.key1");
    }
    @Bean
    public Binding topicBinding2(){
        //*符号代表匹配一个字母，#符号代表匹配0到多个字母
        return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with("topic.#");
    }



    /**
     * Header模式 交换机Exchange
     *
     * */
    @Bean
    public HeadersExchange headersExchange(){
        return new HeadersExchange(HEADERS_EXCHANGE);
    }
    @Bean
    public Queue headerQueue1() {
        return new Queue(HEADER_QUEUE, true);
    }
    @Bean
    public Binding headerBinding() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("header1", "value1");
        map.put("header2", "value2");
        return BindingBuilder.bind(headerQueue1()).to(headersExchange()).whereAll(map).match();
    }

    @Bean
    public Queue businessQueue(){
        log.info("执行方法MQConfig.businessQueue()，初始化RabbitMQ队列：business_queue");
        return new Queue(BUSINESS_QUEUE,true);
    }
}
